/*
 *  Copyright 2015-2016, RenGu Technology (BeiJing) Co., Ltd.
 *  All right reserved.
 *
 *  THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF RENGU TECHNOLOGY (BeiJing) CO., LTD.
 *
 *  THE CONTENTS OF THIS FILE MAY NOT BE DISCLOSED TO THIR PARTIES,
 *  COPIED OR DUPLICATED IN ANY FORM, IN WHOLE OR IN PART,
 *  WITHOUT THE PRIOR WRITTEN PERMISSION OF RENGU TECHNOLOGY (BeiJing) CO., LTD.
 *
 *  VirtAcctTransStatusQueryService
 *
 *  Edit History:
 *      lizhangtao Created on 2020年05月14日
 *
 */
package cc.rengu.igas.acct.core.service.trans;

import cc.rengu.igas.acct.common.constant.AcctCommonConstant;
import cc.rengu.igas.acct.common.dao.AcctDetailMapper;
import cc.rengu.igas.acct.common.dao.impl.AcctDetailMapperImpl;
import cc.rengu.igas.acct.common.entity.AcctDetail;
import cc.rengu.igas.acct.common.enums.AcctRespCodeEnum;
import cc.rengu.igas.acct.common.enums.AcctTransStatusEnum;
import cc.rengu.igas.acct.common.enums.AcctTxnNumEnum;
import cc.rengu.igas.acct.facade.request.VirtAcctTransStatusQueryRequest;
import cc.rengu.igas.acct.facade.response.VirtAcctTransStatusQueryResponse;
import cc.rengu.oltp.service.base.RadpService;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.common.enums.OltpRpcdEnum;
import cc.rengu.oltp.service.common.enums.TransStatusEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.utility.util.ConvertUtil;
import cc.rengu.oltp.utility.util.XmlTreeUtil;
import cc.rengu.utility.base.StringUtil;
import com.alibaba.fastjson.JSONObject;

import java.util.List;

/**
 * 交易状态查询
 *
 * @author lizhangtao
 * @version 1.0
 * @date 2020/5/10
 */
public class VirtAcctTransStatusQueryService extends RadpService {

    @Override
    protected int bizInit(String s) {
        return 0;
    }

    @Override
    protected int bizProcess(String s, int i) {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        try {
            VirtAcctTransStatusQueryRequest virtAcctTransStatusQueryRequest = new VirtAcctTransStatusQueryRequest();
            ConvertUtil.convertOutput(virtAcctTransStatusQueryRequest);
            rglog.info("virtAcctTransStatusQueryRequest = <{}>", JSONObject.toJSONString(virtAcctTransStatusQueryRequest));
            VirtAcctTransStatusQueryResponse virtAcctTransStatusQueryResponse = new VirtAcctTransStatusQueryResponse();
            virtAcctTransStatusQueryResponse.setHeader(virtAcctTransStatusQueryRequest.getHeader());
            BizResponse<VirtAcctTransStatusQueryResponse> bizResponse = new BizResponse<>();
            bizResponse.setResult(virtAcctTransStatusQueryResponse);
            String acctNo = virtAcctTransStatusQueryRequest.getAcctNo();
            String acctType = virtAcctTransStatusQueryRequest.getAcctType();
            String customerId = virtAcctTransStatusQueryRequest.getCustomerId();
            String userId = virtAcctTransStatusQueryRequest.getUserId();
            String userType = virtAcctTransStatusQueryRequest.getUserType();
            //必填项
            if (StringUtil.isNullorEmpty(acctType)) {
                rglog.error("账户类型必输");
                throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(),
                        AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
            }
            if (StringUtil.isNullorEmpty(acctNo) &&
                    StringUtil.isNullorEmpty(customerId) &&
                    (StringUtil.isNullorEmpty(userType) || StringUtil.isNullorEmpty(userId))) {
                //该情况为多商户记账、多商户预授权、多商户预授权撤销、多商户预授权完成交易状态查询
                multiAcctTransQuery(virtAcctTransStatusQueryRequest, virtAcctTransStatusQueryResponse, bizResponse);
            } else {
                //单笔交易查询
                singleAcctTransQuery(virtAcctTransStatusQueryRequest, virtAcctTransStatusQueryResponse, bizResponse);
            }
        } catch (BizException e) {
            try {
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_CODE, e.getCode());
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_DESC, e.getMessage());
            } catch (Exception e1) {
                rglog.error(StringUtil.ExceptionToString(e1));
            }
        } catch (Exception e) {
            rglog.error(StringUtil.ExceptionToString(e));
            try {
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_CODE,
                        OltpRpcdEnum.BIZ_PROCESS_TIMEOUT.getRespCode());
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_DESC,
                        OltpRpcdEnum.BIZ_PROCESS_TIMEOUT.getRespDesc());
            } catch (Exception e1) {
                rglog.error(StringUtil.ExceptionToString(e));
            }
        }
        return 0;
    }

    @Override
    protected int bizTerminate(String s) {
        return 0;
    }

    /**
     * 原交易为一笔包含多账户交易的查询
     *
     * @param virtAcctTransStatusQueryRequest  请求
     * @param virtAcctTransStatusQueryResponse 应答实体
     * @param bizResponse                      dubbo 应答封装
     * @throws BizException 业务异常
     * @throws Exception    其他异常
     */
    private void multiAcctTransQuery(VirtAcctTransStatusQueryRequest virtAcctTransStatusQueryRequest,
                                     VirtAcctTransStatusQueryResponse virtAcctTransStatusQueryResponse,
                                     BizResponse<VirtAcctTransStatusQueryResponse> bizResponse) throws BizException, Exception {
        // 必须上送交易流水号
        if (StringUtil.isNullorEmpty(virtAcctTransStatusQueryRequest.getTransSeqNum())) {
            rglog.error("多商户交易查询必须上送交易流水号");
            throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        }
        // 不能上送记账流水号
        if (!StringUtil.isNullorEmpty(virtAcctTransStatusQueryRequest.getAcctSeqNum())) {
            rglog.error("多商户交易查询不能上送记账流水号");
            throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        }
        List<AcctDetail> acctDetailList;
        AcctDetailMapper acctDetailMapper = new AcctDetailMapperImpl();
        acctDetailList = acctDetailMapper.fetchListByFrontSeqNum(
                virtAcctTransStatusQueryRequest.getHeader().getInstId(), virtAcctTransStatusQueryRequest.getTransSeqNum());
        if (null == acctDetailList || 0 == acctDetailList.size()) {
            //查询本身成功,原交易失败
            setQuerySuccResultFail(virtAcctTransStatusQueryResponse, bizResponse);
            ConvertUtil.convertInput(bizResponse.getResult());
            return;
        }
        String txnNum = acctDetailList.get(0).getTxnNum();
        //只支持多商户交易的查询 单笔记账、预授权、预授权撤销、预授权完成
        if (AcctTxnNumEnum.isSingle(txnNum)) {
            rglog.error("只支持单笔交易的查询 单笔记账、预授权、预授权撤销、预授权完成;而被查询的交易为<{}><{}>", txnNum, AcctTxnNumEnum.getInstance(txnNum).getDesc());
            throw new BizException(AcctRespCodeEnum.ILLEGAL_OPR_ERROR.getRespCode(), AcctRespCodeEnum.ILLEGAL_OPR_ERROR.getRespDesc());
        }
        if (!acctDetailList.stream().allMatch(acctDetail -> acctDetail.getTxnNum().equals(txnNum))) {
            rglog.error("不都是同一个交易，原记账有问题");
            throw new BizException(AcctRespCodeEnum.DB_EXCEPTION.getRespCode(), AcctRespCodeEnum.DB_EXCEPTION.getRespDesc());
        }
        String acctStatus = acctDetailList.get(0).getAcctStatus();
        if (!acctDetailList.stream().allMatch(acctDetail -> acctDetail.getAcctStatus().equals(acctStatus))) {
            rglog.error("不都是同一个状态，原记账有问题");
            throw new BizException(AcctRespCodeEnum.DB_EXCEPTION.getRespCode(), AcctRespCodeEnum.DB_EXCEPTION.getRespDesc());
        }
        String debitCreditFlag = acctDetailList.get(0).getDebitCreditFlag();
        if (!acctDetailList.stream().allMatch(acctDetail -> acctDetail.getDebitCreditFlag().equals(debitCreditFlag))) {
            rglog.error("不都是同一个记账类型，原记账有问题");
            throw new BizException(AcctRespCodeEnum.DB_EXCEPTION.getRespCode(), AcctRespCodeEnum.DB_EXCEPTION.getRespDesc());
        }
        String acctDate = acctDetailList.get(0).getAcctDate();
        if (!acctDetailList.stream().allMatch(acctDetail -> acctDetail.getAcctDate().equals(acctDate))) {
            rglog.error("不都是同一个记账日期，原记账有问题");
            throw new BizException(AcctRespCodeEnum.DB_EXCEPTION.getRespCode(), AcctRespCodeEnum.DB_EXCEPTION.getRespDesc());
        }
        String remark2 = acctDetailList.get(0).getRemark2();
        if (!acctDetailList.stream().allMatch(acctDetail -> acctDetail.getRemark2().equals(remark2))) {
            rglog.error("不都是同一个remark2（记录交易明细总数），原记账有问题");
            throw new BizException(AcctRespCodeEnum.DB_EXCEPTION.getRespCode(), AcctRespCodeEnum.DB_EXCEPTION.getRespDesc());
        }
        //多商户原交易查询，对比成功的交易笔数，针对预授权若已经被撤销或者完成返回该交易已经被撤销或者完成
        int totalRecords = Integer.parseInt(remark2);
        if (totalRecords != acctDetailList.size()) {
            rglog.error("交易笔数对不上，原记账有问题");
            throw new BizException(AcctRespCodeEnum.DB_EXCEPTION.getRespCode(), AcctRespCodeEnum.DB_EXCEPTION.getRespDesc());
        }

        //针对预授权若已经被撤销或者完成返回该交易已经被撤销或者完成
        if (AcctTxnNumEnum.isPreAuth(txnNum)) {
            String remark1 = acctDetailList.get(0).getRemark1();
            if (!acctDetailList.stream().allMatch(acctDetail -> acctDetail.getRemark1().equals(remark1))) {
                rglog.error("不都是同一个remark1（记录预授权是否为撤销或者完成），原记账有问题");
                throw new BizException(AcctRespCodeEnum.DB_EXCEPTION.getRespCode(), AcctRespCodeEnum.DB_EXCEPTION.getRespDesc());
            }
        }
        setQuerySuccResultSucc(virtAcctTransStatusQueryResponse, bizResponse, acctDetailList.get(0));

        ConvertUtil.convertInput(bizResponse.getResult());
    }

    /**
     * 单笔交易查询
     *
     * @param virtAcctTransStatusQueryRequest  请求
     * @param virtAcctTransStatusQueryResponse 应答实体
     * @param bizResponse                      dubbo 应答封装
     * @throws BizException 业务异常
     * @throws Exception    其他异常
     */
    private void singleAcctTransQuery(VirtAcctTransStatusQueryRequest virtAcctTransStatusQueryRequest,
                                      VirtAcctTransStatusQueryResponse virtAcctTransStatusQueryResponse,
                                      BizResponse<VirtAcctTransStatusQueryResponse> bizResponse) throws BizException, Exception {
        String instId = virtAcctTransStatusQueryRequest.getHeader().getInstId();
        String acctNo = virtAcctTransStatusQueryRequest.getAcctNo();
        String customerId = virtAcctTransStatusQueryRequest.getCustomerId();
        String userId = virtAcctTransStatusQueryRequest.getUserId();
        String userType = virtAcctTransStatusQueryRequest.getUserType();
        //单笔交易查询 交易流水号、记账流水号二选一或者都上送
        if (StringUtil.isNullorEmpty(virtAcctTransStatusQueryRequest.getAcctSeqNum()) &&
                StringUtil.isNullorEmpty(virtAcctTransStatusQueryRequest.getTransSeqNum())) {
            rglog.error("单笔交易查询必须上送交易流水号或者记账流水号");
            throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        }
        //查询交易明细
        AcctDetail acctDetail;
        AcctDetailMapper acctDetailMapper = new AcctDetailMapperImpl();
        if (!StringUtil.isNullorEmpty(virtAcctTransStatusQueryRequest.getAcctSeqNum())) {
            acctDetail = acctDetailMapper.selectAcctDetailByAcctSeqNum(instId, virtAcctTransStatusQueryRequest.getAcctSeqNum());
            if (null == acctDetail) {
                rglog.error("机构<{}>记账编号<{}>未查询到数据", instId, virtAcctTransStatusQueryRequest.getAcctSeqNum());
                setQuerySuccResultFail(virtAcctTransStatusQueryResponse, bizResponse);
                ConvertUtil.convertInput(bizResponse.getResult());
                return;
            }
            //若也上送了前端流水号则需要校验
            if (!StringUtil.isNullorEmpty(virtAcctTransStatusQueryRequest.getTransSeqNum())) {
                if (!virtAcctTransStatusQueryRequest.getTransSeqNum().equals(acctDetail.getFrontSeqNum())) {
                    rglog.error("原记账流水号<{}>与原前端上送流水号不为同一个交易", virtAcctTransStatusQueryRequest.getAcctSeqNum(), virtAcctTransStatusQueryRequest.getTransSeqNum());
                    throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
                }
            }
        } else {
            acctDetail = acctDetailMapper.selectAcctDetailByTransSeqNum(instId,
                    virtAcctTransStatusQueryRequest.getTransSeqNum());
            if (null == acctDetail) {
                rglog.error("机构<{}>前端流水号<{}>未查询到数据", instId, virtAcctTransStatusQueryRequest.getTransSeqNum());
                throw new BizException(AcctRespCodeEnum.NO_TRANS_RECORD.getRespCode(), AcctRespCodeEnum.NO_TRANS_RECORD.getRespDesc());
            }
        }
        //校验上送的账号
        if (!StringUtil.isNullorEmpty(acctNo) && !acctNo.equals(acctDetail.getAcctNo())) {
            rglog.error("上送的账号<{}>错误,<{}>", acctNo, acctDetail.getAcctNo());
            throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        }
        //校验上送的客户号
        if (!StringUtil.isNullorEmpty(customerId) && !acctDetail.getCustomerId().equals(customerId)) {
            rglog.error("上送的客户号<{}>错误,<{}>", customerId, acctDetail.getCustomerId());
            throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        }
        //用户类型&用户id不为空校验用户类型&用户id
        if ((!StringUtil.isNullorEmpty(userType) && !StringUtil.isNullorEmpty(userId))) {
            if (!userType.equals(acctDetail.getUserType()) || !userId.equals(acctDetail.getUserId())) {
                rglog.error("上送的外部用户<{}><{}>错误, 记录数据为<{}><{}>", userType, userId, acctDetail.getUserType(), acctDetail.getUserId());
                throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
            }
        }
        //只支持单笔交易的查询 单笔记账、预授权、预授权撤销、预授权完成
        if (!AcctTxnNumEnum.isSingle(acctDetail.getTxnNum())) {
            rglog.error("只支持单笔交易的查询 单笔记账、预授权、预授权撤销、预授权完成;而被查询的交易为<{}><{}>",
                    AcctTxnNumEnum.getInstance(acctDetail.getTxnNum()).getTxnNum(), AcctTxnNumEnum.getInstance(acctDetail.getTxnNum()).getDesc());
            throw new BizException(AcctRespCodeEnum.ILLEGAL_OPR_ERROR.getRespCode(), AcctRespCodeEnum.ILLEGAL_OPR_ERROR.getRespDesc());
        }

        setQuerySuccResultSucc(virtAcctTransStatusQueryResponse, bizResponse, acctDetail);

        ConvertUtil.convertInput(bizResponse.getResult());
    }

    private void setQuerySuccResultFail(VirtAcctTransStatusQueryResponse virtAcctTransStatusQueryResponse,
                                        BizResponse<VirtAcctTransStatusQueryResponse> bizResponse) {
        //查询本身成功,原交易失败
        virtAcctTransStatusQueryResponse.setTransStatus(AcctTransStatusEnum.FAIL.getStatus());
        virtAcctTransStatusQueryResponse.setRespCode(OltpRpcdEnum.TRANS_SUCCESS.getRespCode());
        virtAcctTransStatusQueryResponse.setRespDesc(OltpRpcdEnum.TRANS_SUCCESS.getRespDesc());
        bizResponse.setRspSysId(ChannelEnum.ACCT.getChannelType());
        bizResponse.setRespCode(OltpRpcdEnum.TRANS_SUCCESS.getRespCode());
        bizResponse.setRespDesc(OltpRpcdEnum.TRANS_SUCCESS.getRespDesc());
        bizResponse.setTransStatus(TransStatusEnum.TRANS_SUCC);
    }

    private void setQuerySuccResultSucc(VirtAcctTransStatusQueryResponse virtAcctTransStatusQueryResponse,
                                        BizResponse<VirtAcctTransStatusQueryResponse> bizResponse, AcctDetail acctDetail) {
        //针对预授权若已经被撤销或者完成返回该交易已经被撤销或者完成
        if (AcctTxnNumEnum.isPreAuth(acctDetail.getTxnNum())) {
            //预授权已经被撤销
            if (AcctCommonConstant.CANCELED.equals(acctDetail.getRemark1())) {
                virtAcctTransStatusQueryResponse.setTransStatus(AcctTransStatusEnum.CANCELED.getStatus());
            }
            //预授权已经被完成
            else if (AcctCommonConstant.COMPLETED.equals(acctDetail.getRemark1())) {
                virtAcctTransStatusQueryResponse.setTransStatus(AcctTransStatusEnum.COMPLETED.getStatus());
            }
            //由于只记录成功的因此该情况为成功
            else {
                virtAcctTransStatusQueryResponse.setTransStatus(acctDetail.getAcctStatus());
            }
        } else {
            virtAcctTransStatusQueryResponse.setTransStatus(acctDetail.getAcctStatus());
        }
        //查询本身成功,原交易为成功
        virtAcctTransStatusQueryResponse.setAcctDate(acctDetail.getAcctDate());
        virtAcctTransStatusQueryResponse.setAcctSeqNum(acctDetail.getAcctSeqNum());
        virtAcctTransStatusQueryResponse.setSummary(acctDetail.getSummary());
        virtAcctTransStatusQueryResponse.setRespCode(OltpRpcdEnum.TRANS_SUCCESS.getRespCode());
        virtAcctTransStatusQueryResponse.setRespDesc(OltpRpcdEnum.TRANS_SUCCESS.getRespDesc());
        bizResponse.setRspSysId(ChannelEnum.ACCT.getChannelType());
        bizResponse.setRespCode(OltpRpcdEnum.TRANS_SUCCESS.getRespCode());
        bizResponse.setRespDesc(OltpRpcdEnum.TRANS_SUCCESS.getRespDesc());
        bizResponse.setTransStatus(TransStatusEnum.TRANS_SUCC);
    }
}
